package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"sync/atomic"
	"time"
)

type Account struct {
        Id      int64   `json:"id"`
        Name    string  `json:"name" xorm:"unique"`
        Balance float64 `json:"balance"`
        Version int     `json:"version" xorm:"version"` // Optimistic Locking
}

type Accounts []Account

var myClient = &http.Client{Timeout: 10 * time.Second}

func test_getJson(url string, target interface{}) error {
	r, err := myClient.Get(url)
	if err != nil {
		fmt.Println("err:", err)
		return err
	}
	defer r.Body.Close()

	return json.NewDecoder(r.Body).Decode(target)
}

func test_list() {
	as := Accounts{}
	test_getJson("http://localhost:8080/v1/accounts", &as)
	for _, a := range as {
		fmt.Printf("%#v\n", a)
	}
	println("--------------------------------")
}

func test_get() {
	a := Account{}
	test_getJson("http://localhost:8080/v1/accounts/2", &a)
	fmt.Printf("%#v\n", a)
	println("--------------------------------")
}

func test_post() {
	a := Account{Name: "pig", Balance: 200}

	b, _ := json.Marshal(a)
	body := bytes.NewBuffer([]byte(b))

	r, err := myClient.Post("http://localhost:8080/v1/accounts",
		"application/json", body)
	if err != nil {
		fmt.Println("err:", err)
	}
	defer r.Body.Close()
	println("--------------------------------")
}

func test_curl(url string) {
	for true {
		r, err := myClient.Get(url)
		if err != nil {
			fmt.Println("err:", err)
			return
		}
		defer r.Body.Close()

		body, err := ioutil.ReadAll(r.Body)
		fmt.Printf("%s\n", body)

		time.Sleep(time.Second * 1)
	}
}

func test_auth(url, usr, pwd string) {
	for true {
		req, err := http.NewRequest("GET", url, nil)
		req.SetBasicAuth(usr, pwd)
		r, err := myClient.Do(req)
		if err != nil {
			fmt.Println("err:", err)
			return
		}
		defer r.Body.Close()

		body, err := ioutil.ReadAll(r.Body)
		fmt.Printf("%s", body)

		time.Sleep(time.Second * 1)
	}
}

func test_perf(url string) {
	start := time.Now()
	var readOps uint64 = 0
	for i := 0; i < 100; i++ {
		go func() {
			for start.Add(time.Second * 10).After(time.Now()) {
				r, err := myClient.Get(url)
				if err != nil {
					fmt.Println("err:", err)
					return
				}
				defer r.Body.Close()
				atomic.AddUint64(&readOps, 1)
			}
		}()
	}

	time.Sleep(time.Second * 12)
	readOpsFinal := atomic.LoadUint64(&readOps)
	fmt.Println(readOpsFinal / 10)
}

func main() {
	//	test_list()
	//	test_get()
	//	test_post()
	//	test_list()
	//go test_curl("http://localhost:8080/num")
	//go test_curl("http://localhost:8080/aping")
	//test_auth("http://localhost:8080/aping", "user", "pass")
	test_perf("http://localhost:8080/num")
}
